import 'dart:async';
import 'dart:ui';
import 'package:crypto/crypto.dart';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'dart:async' show Future;
import 'dart:io';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'dart:math';
import 'util/database.dart';
import 'package:path_provider/path_provider.dart';
import 'package:barcode_scan/barcode_scan.dart';
import 'package:flutter/services.dart';

Future<Color> get themeColor async {
  return new Color(int.parse(await getStorage("themeColor") ?? "0xffff5722"));
}

int iosSupportFingerPrint(String model) {
  if (model.contains("iPhone")) {
    int pos = model.indexOf(",");
    int level = int.parse(model.substring(6, pos));
    if (level >= 10) {
      if (model == "iPhone10,1" || model == "iPhone10,2" || model == "iPhone10,4" || model == "iPhone10,5" || model == "iPhone11,2" || model == "iPhone11,4" || model == "iPhone11,6" || model == "iPhone11,8") {
        return 1;
      } else {
        return 2;
      }
    } else if (level > 6) {
      return 1;
    } else {
      return 0;
    }
  } else if (model.contains("iPad")) {
    int pos = model.indexOf(",");
    int level = int.parse(model.substring(4, pos));
    if (level >= 4) {
      return 1;
    } else {
      return 0;
    }
  } else {
    return 0;
  }
}

showProgress(BuildContext context) {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (context) => Center(
          child: CircularProgressIndicator(
            backgroundColor: Colors.deepOrange,
          ),
        ),
  );
}

hideProgress(BuildContext context) {
  Navigator.of(context).pop();
}

void toast(String text) async {
  Fluttertoast.showToast(
    msg: text,
  );
}

String getTimeLong(int time) {
  var time_long = new DateTime.now().millisecondsSinceEpoch - time * 1000;
  return (time_long / 1000 / 60 / 60 / 24).toStringAsFixed(0) + "天";
}

String convertTime(int time, {bool millisecond = false}) {
  if (!millisecond) {
    time = time * 1000;
  }
  var dt = new DateTime.fromMillisecondsSinceEpoch(time);
  return dt.toString().substring(0, 19);
}

String convertBlock(String amount) {
  return (BigInt.parse(amount) / BigInt.from(1000000000000000000)).toStringAsFixed(8);
}

String convertSize(num byte, {int decimal = 1}) {
  if (byte < 1024) {
    return "$byte B";
  } else if (byte < 1024 * 1024) {
    return (byte / 1024).toStringAsFixed(decimal) + "K";
  } else if (byte < 1024 * 1024 * 1024) {
    return (byte / 1024 / 1024).toStringAsFixed(decimal) + "M";
  } else if (byte < 1024 * 1024 * 1024 * 1024) {
    return (byte / 1024 / 1024 / 1024).toStringAsFixed(decimal) + "G";
  } else {
    return (byte / 1024 / 1024 / 1024 / 1024).toStringAsFixed(decimal) + "T";
  }
}

String signPwd(String password) {
  var str = md5.convert(utf8.encode(password)).toString();
  var c1 = str[2], c2 = str[8], c3 = str[17], c4 = str[27];
  str = str.substring(0, 2) + c2 + str.substring(3, 8) + c1 + str.substring(9, 17) + c4 + str.substring(18, 27) + c3 + str.substring(28, 32);
  str = md5.convert(utf8.encode(str)).toString();
  return str;
}

String rand() {
  var r = Random().nextInt(2147483646);
  return r.toString();
}

Future<dynamic> download(String url) async {
  var dir = (await getApplicationDocumentsDirectory()).path;
  var path = "$dir/imgcode-${rand()}.png";
  Dio dio = new Dio();
  Response<HttpClientResponse> response;
  response = await dio.download(url, path);

  var cookie = response.headers['set-cookie'];
  Map res = {"cookie": cookie, "path": path, "response": response};
  return res;
}

Future<dynamic> post({String url, dynamic data, Map<String, dynamic> header, String contentType}) async {
  if (header == null) {
    header = {"Cache-Control": "no-cache"};
    header['user-agent'] = "MineCrafter3/1.5.2 (iPhone; iOS 12.1.2; Scale/2.00)";
  } else {
    header['user-agent'] = "MineCrafter3/1.5.2 (iPhone; iOS 12.1.2; Scale/2.00)";
  }
  if (contentType == null) {
    contentType = "application/x-www-form-urlencoded";
  }
  Dio dio = new Dio(
    new Options(
      connectTimeout: 5000,
      receiveTimeout: 5000,
      contentType: ContentType.parse(contentType),
      headers: header,
    ),
  );
//  dio.onHttpClientCreate = (HttpClient client) {
//    client.findProxy = (uri) {
//      //proxy all request to localhost:8888
//      return "PROXY 192.168.199.196:8888";
//    };
//  };
  Response response;
  try {
    response = await dio.post(
      url,
      data: data,
    );
    var res;
    var cookie = response.headers['set-cookie'];
    if (response.data.runtimeType.toString() == "String") {
      try {
        res = json.decode(response.data);
      } catch (error) {
        print("转码失败");
      }
    } else {
      res = response.data;
    }
    res['cookie'] = cookie;
    return res;
  } catch (error) {
    print("请求出错");
  }
}

Future<dynamic> get(String url, Map data, Map header, {bool decode = true}) async {
  Dio dio = new Dio(
    new Options(
      connectTimeout: 5000,
      receiveTimeout: 5000,
      contentType: ContentType.parse("application/json"),
      headers: header,
    ),
  );
//  dio.onHttpClientCreate = (HttpClient client) {
//    client.findProxy = (uri) {
//      //proxy all request to localhost:8888
//      return "PROXY 192.168.199.196:8888";
//    };
//  };
  try {
    Response response = await dio.get(
      url,
      data: data,
    );
    var res;
    if (response.data.runtimeType.toString() == "String") {
      if (decode != null && decode == false) {
        res = response.data;
      } else {
        res = json.decode(response.data);
      }
    } else {
      res = response.data;
    }
    return res;
  } catch (error) {
    print(error);
  }
}

Future<bool> setStorage(String name, String value) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.setString(name, value);
}

Future<String> getStorage(String name) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.getString(name);
}

Future<bool> removeStorage(String name) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.remove(name);
}

//dynamic jsonDecode(String json){
//  return jsonDecode(json);
//}
Map getParams(Map data, String sessionid, bool isGet) {
  var str = "";
  data.forEach((k, v) {
    str += "$k=$v&";
  });
  str = str.substring(0, str.length - 1);
  str = "$str&key=$sessionid";
  if (isGet) {
    data['sign'] = md5.convert(utf8.encode(str)).toString();
  } else {
    data['key'] = sessionid;
    data['sign'] = md5.convert(utf8.encode(str)).toString();
  }
  return data;
}

Future<List> getGroups() async {
  WankeData groups = new WankeData(tableName: "groups");
  await groups.iniSqlite();
  if (groups.db != null) {
    List<Map> rows = await groups.select();
    return rows;
  } else {
    return null;
  }
}

Future<Map> findGroupByName(String name) async {
  WankeData groups = new WankeData(tableName: "groups");
  await groups.iniSqlite();
  if (groups.db != null) {
    var result = await groups.findByColumn("name", name);
    return result;
  } else {
    return null;
  }
}

Future<List> getDevices() async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    List<Map> rows = await devices.select();
    return rows;
  } else {
    return null;
  }
}

Future<List> getDevicesByGroup(int id) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    List<Map> rows = await devices.selectByColumn("group_id", id);
    return rows;
  } else {
    return null;
  }
}

Future<int> addGroup(String name) async {
  WankeData groups = new WankeData(tableName: "groups");
  await groups.iniSqlite();
  if (groups.db != null) {
    Map<String, dynamic> data;
    data = {"name": name};
    var result = await groups.insert(data);
    return result;
  } else {
    return null;
  }
}

Future<bool> updateGroup(int id, String name) async {
  WankeData groups = new WankeData(tableName: "groups");
  await groups.iniSqlite();
  if (groups.db != null) {
    Map<String, dynamic> data;
    data = {"id": id, "name": name};
    var result = await groups.update(data, "id", id.toString());
    return result > 0;
  } else {
    return false;
  }
}

Future<bool> deleteGroup(int id) async {
  WankeData groups = new WankeData(tableName: "groups");
  await groups.iniSqlite();
  if (groups.db != null) {
    var result = await groups.deleteByColumn("id", id.toString());
    return result > 0;
  } else {
    return false;
  }
}

Future<bool> findDeviceByAccount(String account) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.findByColumn("account", account);
    return result != null;
  } else {
    return false;
  }
}

Future<Map> findDeviceById(dynamic id) async {
  id = id.toString();
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.findByColumn("id", id);
    return result;
  } else {
    return null;
  }
}

Future<Map> getFirstDevice() async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.select();
    if (result != null) {
      return result[0];
    } else {
      return null;
    }
  } else {
    return null;
  }
}

Future<int> getDeviceCount() async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.rowCount();
    return result;
  } else {
    return 0;
  }
}

Future<int> addDeviceBatch(List devices) async {
  WankeData table = new WankeData();
  await table.iniSqlite();
  if (table.db != null) {
    var batch = table.db.batch();
    for (var i = 0; i < devices.length; i++) {
      Map<String, dynamic> data;
      data = {"group_id": 1, "account": devices[i]['phone'], "password": devices[i]['pwd'], "deviceid": rand(), "imeiid": rand(), "sessionid": rand(), "userid": rand(), "name": "获取中", "is_bind": "1"};
      print(data);
      batch.insert("devices", data);
    }
    var res = await batch.commit();
    if (res != null) {
      return res.length;
    } else {
      return 0;
    }
  } else {
    return null;
  }
}

Future<int> addDevice(int group_id, String account, String password, String deviceid, String imeiid, String sessionid, String userid) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    Map<String, dynamic> data;
    data = {"group_id": group_id, "account": account, "password": password, "deviceid": deviceid, "imeiid": imeiid, "sessionid": sessionid, "userid": userid, "name": "获取中", "is_bind": "1"};
    var result = await devices.insert(data);
    return result;
  } else {
    return null;
  }
}

Future<List> selectBlock() async {
  WankeData block = new WankeData(tableName: "block");
  await block.iniSqlite();
  if (block.db != null) {
    var result = await block.select();
    return result;
  } else {
    return null;
  }
}

Future<bool> updateBlockByAddr(String addr, {String note}) async {
  WankeData block = new WankeData(tableName: "block");
  await block.iniSqlite();
  if (block.db != null) {
    Map<String, dynamic> data = {"addr": addr, "last": new DateTime.now().millisecondsSinceEpoch};
    if (note != null) {
      data['note'] = note;
    }
    var result = await block.update(data, "addr", addr);
    return (result != null && result > 0);
  } else {
    return false;
  }
}

Future<bool> addBlock(String addr, String balance, int count) async {
  //尝试更新查询记录，更新成功则返回，否则插入数据
  if (await updateBlockByAddr(addr)) {
    print("存在记录并更新成功");
    return false;
  }
  WankeData block = new WankeData(tableName: "block");
  await block.iniSqlite();
  if (block.db != null) {
    Map<String, dynamic> data;
    data = {"addr": addr, "balance": balance, "count": count, "last": new DateTime.now().millisecondsSinceEpoch};
    var result = await block.insert(data);
    print("保存成功");
    return result > 0;
  } else {
    return false;
  }
}

Future<bool> deleteBlock(int id) async {
  WankeData block = new WankeData(tableName: "block");
  await block.iniSqlite();
  if (block.db != null) {
    var result = await block.deleteByColumn("id", id.toString());
    return result > 0;
  } else {
    return false;
  }
}

Future<bool> updateGroupId(int oldGroup, int newGroup) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var data = {"group_id": newGroup};
    var result = await devices.update(data, "group_id", oldGroup.toString());
    return result > 0 ? true : false;
  } else {
    return false;
  }
}

Future<bool> updateDeviceGroup(int deviceId, int oldGroup, int newGroup) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var data = {"group_id": newGroup, "id": deviceId};
    var result = await devices.update(data, "id", deviceId.toString());
    return result > 0 ? true : false;
  } else {
    return false;
  }
}

Future<bool> deleteDeviceById(int id) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.deleteByColumn("id", id.toString());
    return result > 0 ? true : false;
  } else {
    return false;
  }
}

Future<bool> deleteDeviceByGroupId(int group_id) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.deleteByColumn("group_id", group_id.toString());
    return result > 0 ? true : false;
  } else {
    return false;
  }
}

Future<bool> updateDevice(
    {int id,
    String device_name,
    String password,
    String sessionid,
    String userid,
    int capacity_1,
    int used_1,
    int capacity_2,
    int used_2,
    String addr,
    String device_id,
    String device_sn,
    String peerid,
    String system_version,
    String ip_addr,
    String mac_address,
    String lan_ip,
    String province,
    String city,
    String isp,
    String status,
    String bind_time,
    String bind_days,
    String hardware_model,
    String is_bind,
    String iswanke,
    String ispush,
    int group_id,
    double yesterday_income,
    double prevday_income,
    double balance_income,
    double total_income,
    String income_day}) async {
  if (id == null) return false;
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    Map<String, dynamic> data = {"id": id};
    if (device_name != null) data['device_name'] = device_name;
    if (password != null) data['password'] = password;
    if (sessionid != null) data['sessionid'] = sessionid;
    if (userid != null) data['userid'] = userid;
    if (capacity_1 != null) data['capacity_1'] = capacity_1;
    if (used_1 != null) data['used_1'] = used_1;
    if (capacity_2 != null) data['capacity_2'] = capacity_2;
    if (used_2 != null) data['used_2'] = used_2;
    if (addr != null) data['addr'] = addr;
    if (device_id != null) data['device_id'] = device_id;
    if (device_sn != null) data['device_sn'] = device_sn;
    if (peerid != null) data['peerid'] = peerid;
    if (system_version != null) data['system_version'] = system_version;
    if (ip_addr != null) data['ip_addr'] = ip_addr;
    if (ip_addr != null) data['ip_addr'] = ip_addr;
    if (mac_address != null) data['mac_address'] = mac_address;
    if (lan_ip != null) data['lan_ip'] = lan_ip;
    if (province != null) data['province'] = province;
    if (city != null) data['city'] = city;
    if (isp != null) data['isp'] = isp;
    if (status != null) data['status'] = status;
    if (bind_time != null) data['bind_time'] = bind_time;
    if (bind_days != null) data['bind_days'] = bind_days;
    if (hardware_model != null) data['hardware_model'] = hardware_model;
    if (is_bind != null) data['is_bind'] = is_bind;
    if (iswanke != null) data['iswanke'] = iswanke;
    if (ispush != null) data['ispush'] = ispush;
    if (yesterday_income != null) data['yesterday_income'] = yesterday_income;
    if (prevday_income != null) data['prevday_income'] = prevday_income;
    if (balance_income != null) data['balance_income'] = balance_income;
    if (total_income != null) data['total_income'] = total_income;
    if (income_day != null) data['income_day'] = income_day;
    var result = await devices.update(data, "id", id.toString());
    if (result > 0) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
}

Map json_decode(String json) {
  return jsonDecode(json);
}

String json_encode(dynamic data) {
  return jsonEncode(data);
}

Future<Map> QQLogin(String openid, String nickname, String avatar) async {
  Map<String, dynamic> data = {"qqopenid": openid, "nickname": nickname, "avatar": avatar};
  FormData formData = new FormData.from(data);
  var res = await post(url: "https://www.fmtol.com/Home/App/qqlogin", data: formData);
  return res;
}

Future<Map> bindQQ(String uid, String openid, String nickname, String avatar) async {
  Map<String, dynamic> data = {"uid": uid, "qqopenid": openid, "nickname": nickname, "avatar": avatar};
  FormData formData = new FormData.from(data);
  var res = await post(url: "https://www.fmtol.com/Home/App/bindqq", data: formData);
  return res;
}

Future<Map> unBindQQ(String uid) async {
  Map<String, dynamic> data = {
    "uid": uid,
  };
  FormData formData = new FormData.from(data);
  var res = await post(url: "https://www.fmtol.com/Home/App/unbindqq", data: formData);
  return res;
}

Future<Map> bindAccount(String uid, String username, String password) async {
  Map<String, dynamic> data = {"uid": uid, "username": username, "password": password};
  FormData formData = new FormData.from(data);
  var res = await post(url: "https://www.fmtol.com/Home/App/bindaccount", data: formData);
  return res;
}

Future<Map> unBindAccount(String uid) async {
  Map<String, dynamic> data = {"uid": uid};
  FormData formData = new FormData.from(data);
  var res = await post(url: "https://www.fmtol.com/Home/App/unbindaccount", data: formData);
  return res;
}

Future<Map> userLogin(String username, String password) async {
  Map<String, dynamic> data = {"username": username, "password": password};
  FormData formData = new FormData.from(data);
  var res = await post(url: "https://www.fmtol.com/Home/App/userlogin", data: formData);
  return res;
}

Future<Map> userRegister(String username, String password) async {
  Map<String, dynamic> data = {"username": username, "password": password};
  FormData formData = new FormData.from(data);
  var res = await post(url: "https://www.fmtol.com/Home/App/userregister", data: formData);
  return res;
}

Future getQQInfo(String access_token, String openid) async {
  var url = "https://graph.qq.com/user/get_user_info";
  var key = 101475558;
  if (Platform.isIOS) {
    key = 101218757;
  }
  var data = {"access_token": access_token, "oauth_consumer_key": key, "openid": openid};
  var res = await get(url, data, null);
  return res;
}

Future<Map> checkSmsCode(String account, String smsCode) async {
  Map data = {};
  if (account.contains("@")) {
    data['account_type'] = "1";
    data['mail'] = account;
    data['nc'] = "IN";
    data['phone_area'] = "Email";
    data['smscode'] = smsCode;
  } else {
    data['deviceid'] = rand();
    data['imeiid'] = rand();
    data['phone'] = account;
    data['smscode'] = account;
  }
  var url = "https://api-accw.onethingpcs.com/sys/checksmscode?appversion=1.5.2";
  data = getParams(data, "", false);
  var res = await post(url: url, data: data);
  return res;
}

Future<Map> doRegister(String account, String password, String smsCode) async {
  Map data = {};
  var header = {"Accept-Language": "zh-Hans-CN;q=1", "Cookie": "origin=2"};
  if (account.contains("@")) {
    data['account_type'] = "1";
    data['deviceid'] = rand();
    data['imeiid'] = rand();
    data['mail'] = account;
    data['nc'] = "GB";
    data['pwd'] = signPwd(password);
    data['smscode'] = smsCode;
  } else {
    data['deviceid'] = rand();
    data['imeiid'] = rand();
    data['phone'] = account;
    data['pwd'] = signPwd(password);
    data['smscode'] = account;
  }
  var url = "https://api-accw.onethingpcs.com/user/setpwd?appversion=1.5.2";
  data = getParams(data, "", false);
  var res = await post(url: url, data: data, header: header);
  print(res);
  return res;
}

Future<Map> doLogin({
  int id,
  String account,
  String password,
  String deviceid,
  String imeiid,
}) async {
  if (deviceid == null) deviceid = rand();
  if (imeiid == null) imeiid = rand();
  Map data;
  //判断账号类型
  if (account.contains("@")) {
    data = {
      'account_type': '5',
      'deviceid': deviceid,
      'imeiid': imeiid,
      'mail': account,
      'phone_area': "Email",
      'pwd': signPwd(password),
    };
  } else {
    data = {
      'account_type': '4',
      'deviceid': deviceid,
      'imeiid': imeiid,
      'phone': account,
      'pwd': signPwd(password),
    };
  }
  var url = "https://api-accw.onethingpcs.com/user/login?appversion=1.5.2";

  data = getParams(data, "", false);
  var res = await post(url: url, data: data);
  if (res == null) {
    return null;
  }
  if (res['iRet'] == 0) {
    print(res);
    List<String> cookies = res['cookie'];
    Map info = {"sessionid": "", "userid": ""};
    cookies.forEach((cookie) {
      if (cookie.contains("sessionid")) {
        info['sessionid'] = res['data']['sessionid'];
      } else if (cookie.contains("userid")) {
        info['userid'] = cookie.substring(7, 14);
      }
    });
    print(info);
    updateDevice(id: id, sessionid: info['sessionid'], userid: info['userid']);
    return info;
  } else {
    //toast(res['sMsg']);
    return null;
  }
}

Future<bool> checkLogin(
  String sessionid,
  String userid,
) async {
  var url = 'https://api-accw.onethingpcs.com/user/check-session?appversion=1.5.2';
  var header = {"Cookie": "sessionid=$sessionid; userid=$userid"};
  var sign = md5.convert(utf8.encode("&key=$sessionid"));
  var data = {"sign": sign};
  var res = await post(url: url, data: data, header: header);
  print(res);
  if (res == null) {
    return false;
  }
  if (res['iRet'] == 0) {
    return true;
  } else {
    return false;
  }
}

Future<bool> setDeviceName(String sessionid, String userid, String device_id, String device_name) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 1, "deviceid": device_id, "devicename": device_name, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/setDeviceName";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] == 0) {
    return true;
  } else {
    toast(res['msg']);
    return false;
  }

//  if (res['rtn'] != 0) {
//    return null;
//  } else {
//    List bindDevices = res['result'][1]['devices'];
//    return bindDevices;
//  }
}

Future<List> getDeviceInfo(String sessionid, String userid) async {
  Map<String, dynamic> data = {'appversion': '1.5.2', 'ct': 2, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/listPeer";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  print(res);
  if (res['rtn'] != 0) {
    return null;
  } else {
    List bindDevices = res['result'][1]['devices'];
    return bindDevices;
  }
}

void showPopupMenu<T>(BuildContext context, State state, {double elevation = 8.0, @required List<PopupMenuEntry<T>> items, T initialValue, PopupMenuCanceled onCanceled, PopupMenuItemSelected<T> onSelected, double offsetX = 0.0, double offsetY = 0.0}) {
  final RenderBox button = context.findRenderObject();
  final RenderBox overlay = Overlay.of(context).context.findRenderObject();
  final RelativeRect position = new RelativeRect.fromRect(
    new Rect.fromPoints(
      button.localToGlobal(new Offset(offsetX, offsetY), ancestor: overlay),
      button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay),
    ),
    Offset.zero & overlay.size,
  );
  showMenu<T>(
    context: context,
    elevation: elevation,
    items: items,
    initialValue: initialValue,
    position: position,
  ).then<void>((T newValue) {
    if (!state.mounted) return null;
    if (newValue == null) {
      if (onCanceled != null) onCanceled();
      return null;
    }
    if (onSelected != null) onSelected(newValue);
  });
}

Future<bool> bindDevice(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 2, 'deviceid': device_id, 'userud': userid, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/bind";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    toast(res['msg']);
    return false;
  } else {
    toast("绑定成功");
    return true;
  }
}

Future<bool> unBindDevice(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'deviceid': device_id, 'nc': 'IN', 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/unbind";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    toast(res['msg']);
    return false;
  } else {
    toast("解绑成功");
    return true;
  }
}

Future<bool> unMountDisk(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 1, 'deviceid': device_id, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/umountUSBDisk";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    toast(res['msg']);
    return false;
  } else {
    toast("弹出磁盘成功");
    return true;
  }
}

Future<bool> resetDevice(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 1, 'deviceid': device_id, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/deviceReset";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    toast(res['msg']);
    return false;
  } else {
    toast("设备重置成功");
    return true;
  }
}

Future<Map> getDeviceMessage(String sessionid, String userid, String peerid, int page) async {
  var header = {"Cookie": "ct=2; origin=2; peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {
    "page": page.toString(),
  };
  print(data);
  data = getParams(data, sessionid, true);
  var res = await post(url: "https://account.onethingpcs.com/msgcenter/list?appversion=1.5.2", header: header, data: data);
  return res;
}

Future<Map> getDrawRecord(String sessionid, String userid, int page) async {
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var data = {
    "page": page,
  };
  var res = await post(url: "https://api-accw.onethingpcs.com/wkb/outcome-history", header: header, data: data);
  return res;
}

Future<Map> getSmsCode(String account, {String sessionid, String userid, String imgCode, String codeKey1, String codeKey2}) async {
  Map data = {};
  var header;
  //判断账号类型
  if (codeKey1 != null) {
    header = {"Cookie": "sessionid=$sessionid; userid=$userid;img_verify_code_key=$codeKey1;img_verify_code_key2=$codeKey2", "Accept-Language": "zh-Hans-CN;q=1"};
  } else if (sessionid != null) {
    header = {"Cookie": "sessionid=$sessionid; userid=$userid;", "Accept-Language": "zh-Hans-CN;q=1"};
  } else {
    header = {"Accept-Language": "zh-Hans-CN;q=1"};
  }
  if (account.contains("@")) {
    data['account_type'] = "1";
    data['appversion'] = '1.5.2';
    if (imgCode != null) {
      data['img_code'] = imgCode;
    }
    data['mail'] = account;
    data['nc'] = "GB";
    data['type'] = "1";
  } else {
    data['appversion'] = '1.5.2';
    if (imgCode != null) {
      data['img_code'] = imgCode;
    }
    data['type'] = "1";
    data['phone'] = account;
  }
  var url = "https://api-accw.onethingpcs.com/sys/getsmscode?appversion=1.5.2";

  data = getParams(data, sessionid, true);
  var res = await post(url: url, data: data, header: header);
  return res;
}

Future<Map> getImageCode(String url) async {
  var downResult = await download(url);
  List<String> cookies = downResult['cookie'];
  Map res = {
    "path": downResult['path'],
  };
  cookies.forEach((cookie) {
    if (cookie.contains("img_verify_code_key2")) {
      res['codeKey2'] = cookie.substring(21, 53);
    } else if (cookie.contains("img_verify_code_key")) {
      res['codeKey1'] = cookie.substring(20, 52);
    }
  });
  return res;
}

Future<Map> unbindWallet(String addr, String smsCode, String sessionid, String userid) async {
  var header = {"Cookie": "sessionid=$sessionid; userid=$userid;"};
  Map data = {
    "addr": addr,
    "appversion": "1.5.2",
    "smscode": smsCode,
  };
  var url = "https://api-accw.onethingpcs.com/wkb/unbind-addr?appversion=1.5.2";
  data = getParams(data, sessionid, false);
  var res = await post(url: url, data: data, header: header);
  return res;
}

Future<Map> bindWallet(String addr, String smsCode, String sessionid, String userid, String device_id) async {
  var header = {"Cookie": "sessionid=$sessionid; userid=$userid;"};
  Map data = {
    "addr": addr,
    "appversion": "1.5.2",
    "device_id": device_id,
    "smscode": smsCode,
  };
  var url = "https://api-accw.onethingpcs.com/wkb/bind-addr?appversion=1.5.2";
  data = getParams(data, sessionid, false);
  var res = await post(url: url, data: data, header: header);
  return res;
}

Future<Map> remoteLogin(String sessionid, String userid, String peerid) async {
  var url = "https://control-remotedl.onethingpcs.com/login";
  var header = {"Cookie": "origin=2; peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {
    "pid": peerid,
    "v": 2,
    "ct": 33,
  };
  var res = await get(url, data, header);
  return res;
}

Future<Map> getDownloadTask(String sessionid, String userid, String peerid, int type) async {
  var url = "https://control-remotedl.onethingpcs.com/list";
  var header = {"Cookie": "origin=2;peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {"pid": peerid, "v": 2, "ct": 33, "pos": 0, "number": 20, "type": type, "needUrl": 1};

  var res = await get(url, data, header);
  return res;
}

Future<Map> downloadStart(String sessionid, String userid, String peerid, List<String> tasks) async {
  var url = "https://control-remotedl.onethingpcs.com/start";
  var header = {"Cookie": "origin=2;peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {"pid": peerid, "v": 2, "ct": 33, "tasks": tasks.join(",")};

  var res = await get(url, data, header);
  return res;
}

Future<Map> downloadPause(String sessionid, String userid, String peerid, List<String> tasks) async {
  var url = "https://control-remotedl.onethingpcs.com/pause";
  var header = {"Cookie": "origin=2;peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {"pid": peerid, "v": 2, "ct": 33, "tasks": tasks.join(",")};

  var res = await get(url, data, header);
  return res;
}

Future<Map> downloadDelete(String sessionid, String userid, String peerid, List<String> tasks, bool deleteFile) async {
  var url = "https://control-remotedl.onethingpcs.com/del";
  var header = {"Cookie": "origin=2;peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {"pid": peerid, "v": 2, "ct": 33, "tasks": tasks.join(","), "deleteFile": "$deleteFile", "recycleTask": "false"};
  var res = await get(url, data, header);
  return res;
}

Future<Map> urlResolve(String sessionid, String userid, String peerid, String link) async {
  var url = "https://control-remotedl.onethingpcs.com/urlResolve?pid=$peerid&v=2";
  var header = {"Cookie": "origin=2;peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {"url": link};
  var res = await post(url: url, data: data, contentType: "application/json", header: header);
  return res;
}

Future<Map> createDlTask(String sessionid, String userid, String peerid, String link, String name, dynamic size, bool disk1) async {
  var url = "https://control-remotedl.onethingpcs.com/createTask?pid=$peerid&v=2&ct=33";
  var header = {"Cookie": "origin=2;peerid=$peerid; sessionid=$sessionid; userid=$userid"};
  var data = {
    "path": "/media/${disk1 ? "sda1" : "sdb1"}/onecloud/tddownload",
    "tasks": [
      {"gcid": "", "filesize": size, "url": link, "cid": ""}
    ]
  };
  var res = await post(url: url, data: data, contentType: "application/json", header: header);
  return res;
}

Future<Map> getBlockInfo(String addr, int lasttime) async {
  var data = '["$addr","0","$lasttime","1","20"]';
  var res = await post(url: "https://walletapi.linktoking.com/getTransactionRecords", data: data);
  return res;
}

Future<Map> getBlockBalance(String addr) async {
  var data = '{"jsonrpc": "2.0","method": "eth_getBalance","params": ["$addr", "latest"],"id": 1}';
  var res = await post(url: "https://walletapi.linktoking.com/getBalance", data: data);
  return res;
}

Future<Map> applyToDraw(String sessionid, String userid) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'gasType': 2};
  data = getParams(data, sessionid, false);
  var url = "https://api-accw.onethingpcs.com/wkb/draw";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await post(url: url, header: header, data: data);
  return res;
}

Future<Map> getIncomeRecord({String sessionid, String userid, int year, int month}) async {
  var last_month;
  if (year == null && month == null) {
    last_month = "0";
  } else {
    if (year == null) year = new DateTime.now().year;
    if (month == null) month = new DateTime.now().month + 1;
    last_month = year.toString() + (month > 9 ? month.toString() : "0" + month.toString());
  }
  Map<String, dynamic> data = {'appversion': '1.5.10', 'last_month': last_month};
  data = getParams(data, sessionid, true);
  var url = "https://api-accw.onethingpcs.com/wkb/income-history";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res == null) {
    return null;
  }
  if (res['iRet'] == 0) {
    return res['data'];
  } else {
    return null;
  }
}

String getDate([int offset = 0]) {
  DateTime date = new DateTime.now().add(new Duration(days: offset));
  var year = date.year;
  var month = date.month;
  var day = date.day;
  return "$year${month > 9 ? "$month" : "0$month"}${day > 9 ? "$day" : "0$day"}";
}

Future<Map> getAccountInfo({String sessionid, String userid}) async {
  var url = "https://api-accw.onethingpcs.com/wkb/account-info?appversion=1.5.2";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};

  Map<String, dynamic> data = {'cookie': 'sessionid=$sessionid'};
  data = getParams(data, sessionid, true);
//  var data = {"sessionid": sessionid};
  print(header);
  var res = await post(url: url, data: data, header: header);
  print(res);
  if (res == null) {
    return null;
  }
  if (res['iRet'] == 0) {
    return res['data'];
  } else {
    return null;
  }
}

Future<Map> getUsbInfo(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 2, 'deviceid': device_id, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/getUSBInfo";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  print(res);
  if (res == null) {
    return null;
  }
  if (res['rtn'] != 0) {
    return null;
  } else {
    int capacity_1 = 0;
    int used_1 = 0;
    int capacity_2 = 0;
    int used_2 = 0;
    List disks = res['result'][1]['partitions'];
    int count = disks.length;
    if (count == 1) {
      capacity_1 = int.parse(disks[0]['capacity']);
      used_1 = int.parse(disks[0]['used']);
    } else if (count == 2) {
      capacity_1 = int.parse(disks[0]['capacity']);
      used_1 = int.parse(disks[0]['used']);
      capacity_2 = int.parse(disks[1]['capacity']);
      used_2 = int.parse(disks[1]['used']);
    }
    Map usbInfo = {"count": count, "capacity_1": capacity_1, "used_1": used_1, "capacity_2": capacity_2, "used_2": used_2};
    return usbInfo;
  }
}

Future<Map> getUserInfo(String uid) async {
  var jpushid = await getStorage("jpushid");
  Map<String, dynamic> data = {"uid": uid, "jpushid": jpushid ?? ""};
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/App/getInfo";
  var res = await post(url: url, data: formData);
  return res;
}

Future<Map> getWankeTop() async {
  var url = "https://api-accw.onethingpcs.com/info/query";
  var res = await post(url: url);
  return res;
}

Future<Map> saveCloudBackup(String uid, String accounts) async {
  Map<String, dynamic> data = {
    "uid": uid,
    "accounts": accounts,
  };
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/App/saveCloudBackup";
  var res = await post(url: url, data: formData);
  return res;
}

Future<Map> getCloudBackup(String uid) async {
  Map<String, dynamic> data = {
    "uid": uid,
  };
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/App/getCloudBackup";
  var res = await post(url: url, data: formData);
  return res;
}

Future<Map> getPushAccount(String uid) async {
  Map<String, dynamic> data = {
    "uid": uid,
  };
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/User/importPush";
  var res = await post(url: url, data: formData);
  return res;
}

Future<Map> getWebAccount(String code) async {
  Map<String, dynamic> data = {
    "code": code,
  };
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/User/getImport";
  var res = await post(url: url, data: formData);
  return res;
}

Future<Map> checkPay(String uid, String trade_no) async {
  Map data = {
    "uid": uid,
    "trade_no": trade_no,
  };
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/Pay/checkAlipay";
  var res = await post(url: url, data: formData);
  return res;
}

Future<Map> saveMonitor(List devices, String uid) async {
  Map<String, dynamic> data = {"data": base64Encode(utf8.encode(json_encode(devices))), "uid": uid};
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/App/saveMonitor";
  var res = await post(url: url, data: formData);
  return res;
}

Future<Map> setMonitor(Map<String, dynamic> data) async {
  FormData formData = new FormData.from(data);
  var url = "https://www.fmtol.com/Home/App/setMonitor";
  var res = await post(url: url, data: formData);
  return res;
}

Future<String> scan() async {
  try {
    String barcode = await BarcodeScanner.scan();
    return barcode;
  } on PlatformException catch (e) {
    if (e.code == BarcodeScanner.CameraAccessDenied) {
      toast("请先允许玩客随行访问摄像头");
    } else {
      toast("扫码失败");
    }
    return null;
  } on FormatException {
    toast("扫码失败");
    return null;
  } catch (e) {
    toast("扫码失败");
    return null;
  }
}
